package controller;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.sql.Timestamp;
import java.util.ArrayList;


import javax.swing.JOptionPane;




import model.AppModel;
import model.Email;
import model.EmailBuilder;

import model.ModelException;
import model.Template;
import model.TemplateCompiler;

import view.ComposeMailMainMenu;
import view.ComposeMailView;
import view.EmailEditorPanel;
import view.ViewHelpers;

/**
 * Controller for compose email view
 * 
 * @author Farzana Alam (farzana22@gmail.com)
 * @since May 2013
 * @version $Revision: 1.0 $
 */
public class ComposeMailController {

	// The email object
	private Email emailObj; // 0 means new email

	// The app model
	private AppModel model;
	
	// The app main controller
	private AppController appController;

	// View to control
	private ComposeMailView view;

	// Components under the View to control
	private EmailEditorPanel editorPanel;
	private ComposeMailMainMenu mainMenu;

	// hold current body state
	private String bodyHolder;
	
	/**
	 * Construct with an initial email object (can be null). Also takes the app model
	 * @param emailObj
	 * @param model
	 * @param appController 
	 */
	public ComposeMailController(Email emailObj, AppModel model, AppController appController) {
	
		this.emailObj = emailObj;
		this.model = model;
		this.appController = appController;

		
		setupView();
		mainMenu = view.getMainMenu();
		editorPanel = view.getEmailEditorPanel();
		assignHandlersToEvent();
	}

	/**
	 * Sets up the view based on the current data
	 */
	private void setupView() {
		
		// Setup the email window based on new or draft email
		if (emailObj == null) {
			view = new ComposeMailView(true, model.getUser().getName(), "");
		} else {
			view = new ComposeMailView(false, emailObj.getFrom(), emailObj.getSubject());
			view.getEmailEditorPanel().getTo().setText(emailObj.getTo());
			view.getEmailEditorPanel().getSubject().setText(emailObj.getSubject());
			view.getEmailEditorPanel().getBody().setText(emailObj.getBody());
		}

		// Load all the templates into the combobox
		for(Template template : model.getUser().getTemplates()){
			view.getEmailEditorPanel().getEmailTemplates().addElement(template.getTitle());
		}

	}

	/**
	 * Add listeners and handling functions
	 */
	private void assignHandlersToEvent() {

		// Window closing event
		view.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				actionClose();
			}
		});
		
		// Main menu (New message)
		mainMenu.getNewMessage().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				new ComposeMailController(null, model, appController);
			}
		});

		// Main menu (close)
		mainMenu.getCloseWindow().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionClose();
			}
		});
		
		// Main menu (Save as draft)
		mainMenu.getSaveMail().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionClose();
			}
		});

		// Main menu send email now
		mainMenu.getSendMail().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionSend();
			}
		});

		// Send button
		editorPanel.getSendButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				actionSend();
			}
		});

		// Save button
		editorPanel.getSaveButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionSave();
			}
		});
		
		// Preview button press and release
		view.getEmailEditorPanel().getPreviewButton().addMouseListener(new MouseListener() {
			
			@Override
			public void mouseReleased(MouseEvent arg0) {
				actionPreviewReleased();
			}
			
			@Override
			public void mousePressed(MouseEvent arg0) {
				actionPreviewPressed();
			}
			
			@Override
			public void mouseExited(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseEntered(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseClicked(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}
		});
		
		// Template change
		view.getEmailEditorPanel().getEmailTemplatesCombobox().addItemListener(new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent itemEvt) {
		        if (itemEvt.getStateChange() == ItemEvent.SELECTED){
		        	actionChangeBodyTemplate();
		        }
			}
		});
		
	}

	/**
	 * Replaces back the original body
	 */
	protected void actionPreviewReleased() {
		view.getEmailEditorPanel().getBody().setText(bodyHolder);
		view.getEmailEditorPanel().getBody().setBackground(Color.white);
	}

	/**
	 * Replaces the current body with the compiled one
	 */
	protected void actionPreviewPressed() {
		
		bodyHolder = view.getEmailEditorPanel().getBody().getText();
		view.getEmailEditorPanel().getBody().setBackground(Color.yellow);
		
		// Temporarily creating a preview
		TemplateCompiler templateCompiler = new TemplateCompiler();
		templateCompiler.setTokens(model.getUser().getTokenHashMap());
		
		String[] toArr = view.getEmailEditorPanel().getTo().getText().split(",");
		String to = toArr[0].trim();
		String from = view.getEmailEditorPanel().getFrom().getText().trim();

		templateCompiler.addOrReplaceToken("to", to);
		templateCompiler.addOrReplaceToken("from", from);
		
		templateCompiler.setBody(view.getEmailEditorPanel().getBody().getText());
		view.getEmailEditorPanel().getBody().setText(templateCompiler.compile());
		
	}

	/**
	 * Changes the body template
	 */
	protected void actionChangeBodyTemplate() {
		
		boolean proceed = true;
		
		if (!view.getEmailEditorPanel().getBody().getText().isEmpty()){
			if (!ViewHelpers.confirm("Changing template will replace existing body, are you sure?")){
				proceed = false;
			}
		}
		
		if (proceed){
			
			String templateTitle = view.getEmailEditorPanel().getEmailTemplatesCombobox().getSelectedItem().toString();
			
			if (templateTitle.equalsIgnoreCase("None")){
				view.getEmailEditorPanel().getBody().setText("");
			} else {
				String body = model.getUser().getTemplate(templateTitle).getBody();
				view.getEmailEditorPanel().getBody().setText(body);
			}
		}
	}

	/**
	 * Save the email to the database and add it to the folders object
	 */
	private void actionSave() {

		// Completely new email
		if (emailObj == null) {

			// Create a new email object
			emailObj = new EmailBuilder()
					.setTo(view.getEmailEditorPanel().getTo().getText())
					.setFrom(model.getUser().getName())
					.setSubject(view.getEmailEditorPanel().getSubject().getText())
					.setBody(view.getEmailEditorPanel().getBody().getText())
					.setRead(true)
					.setFolderId(model.getUser().getFolder("Drafts").getId())
					.setTimestamp(new Timestamp(new java.util.Date().getTime()))
					.build();
			// Save it to the database and add to the user's draft folder
			try {
				emailObj.save();
			} catch (ModelException e) {
				System.out.println("Could not save the email object");
			}
			
			model.getUser().getFolder("Drafts").getEmails().add(emailObj);
		}

		// If its an existing email then update the model and save in the db
		else {
			try {
				// Update the model
				emailObj.setTo(view.getEmailEditorPanel().getTo().getText());
				emailObj.setFrom(view.getEmailEditorPanel().getFrom().getText());
				emailObj.setSubject(view.getEmailEditorPanel().getSubject().getText());
				emailObj.setBody(view.getEmailEditorPanel().getBody().getText());
				emailObj.setRead(true);
				emailObj.setFolderId(model.getUser().getFolder("Drafts").getId());
				emailObj.setTimestamp(new Timestamp(new java.util.Date().getTime()));
				// Save to db
				emailObj.save();
			} catch (ModelException e) {
				System.out.println("Could not save the email object");
			}
		}
		
		appController.getNavigationController().refreshNavigationFolders("Drafts");
		view.dispose();
	}

	/**
	 * Confirms if the email should be saved in drafts or not
	 */
	private void actionClose() {

		int option = JOptionPane.showConfirmDialog(null, "Save the email ?");
		if (option == JOptionPane.YES_OPTION) {
			actionSave();
		} else if (option == JOptionPane.NO_OPTION) {
			view.dispose();
		}
	}

	/**
	 * Saves the email in the outbox folder for later sending
	 */
	private void actionSend() {
		
		if (view.getEmailEditorPanel().getTo().getText().isEmpty()){
			ViewHelpers.alertError("The 'to' address cannot be left empty");
			return;
		}
		
		boolean isNewEmail = false;
		
		// Completely new email
		if (emailObj == null) {
			
			isNewEmail = true;

			// Create a new email object and save it in the toSend folder
			emailObj = new EmailBuilder()
					.setTo(view.getEmailEditorPanel().getTo().getText())
					.setFrom(model.getUser().getName())
					.setSubject(view.getEmailEditorPanel().getSubject().getText())
					.setBody(view.getEmailEditorPanel().getBody().getText())
					.setRead(true)
					.setTimestamp(new Timestamp(new java.util.Date().getTime()))
					.build();
			
		}
		
		
		emailObj.setFolderId( model.getUser().getFolder("Outbox").getId() );
		model.getUser().getFolder( model.getUser().getFolder("Outbox").getId() ).getEmails().add(emailObj);
		
		if (! isNewEmail){
			model.getUser().getFolder( model.getUser().getFolder("Drafts").getId() ).getEmails().remove(emailObj);
		}

		
		try {
			emailObj.save();
		} catch (ModelException e) {
			System.out.println("Could not save the email object to persistent");
		}
		
		ArrayList<Email> emails = new ArrayList<Email>();
		emails.add(emailObj);
		
//		ObjectOutputStream os;
		try {
//			System.out.println("SENDING THIS EMAIL TO SERVER");
//			os = new ObjectOutputStream(model.serverSocket.getOutputStream());
			model.getOsStream().writeObject(new String("emails"));
			model.getOsStream().writeObject(emails);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		appController.getNavigationController().refreshNavigationFolders("Outbox");
		view.dispose();
	}

	// Setting From field in the editor with respective email address
	/**
	 * Method set_fromAddressText.
	 * @param _fromAddressText String
	 */
	public void set_fromAddressText(String _fromAddressText) {
		editorPanel.getFrom().setText(_fromAddressText);
	}

}
